
/**
 * gash - Implementation of an own shell 
 *  
 * Author: Gabriel Gomes
 * Date: Mar, 2009
 *
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */


#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <malloc.h>
#include <sys/dir.h>
#include <sys/stat.h>
#include <fcntl.h>



#define MAXBUFFER 1024
#define PARAM 10

extern char **environ;
static char *my_argv[100],*my_envp[100];
static char *search_path[10];
int op;


/*
 * Function that does the handle signal
 */
void handle_signal(int signo)
{
    printf("\ngash> ");
    fflush(stdout);
}


/*
 * Function that gets the path from the so
 */
void get_path_string(char **tmp_envp, char *bin_path)
{
	int count = 0;
	char *tmp;
	while(1) {
		tmp = strstr(tmp_envp[count], "PATH");
		if(tmp == NULL) {
			count++;
		} else {
			break;
		}
	}
        strncpy(bin_path, tmp, strlen(tmp));
}

/*
 * Function that inserts the path string to search
 */

void insert_path_str_to_search(char *path_str) 
{
	int index=0;
	char *tmp = path_str;
	char ret[100];

	while(*tmp != '=')
		tmp++;
	tmp++;

	while(*tmp != '\0') {
		if(*tmp == ':') {
			strncat(ret, "/", 1);
			search_path[index] = (char *) malloc(sizeof(char) * (strlen(ret) + 1));
			strncat(search_path[index], ret, strlen(ret));
			strncat(search_path[index], "\0", 1);
			index++;
			bzero(ret, 100);
		} else {
			strncat(ret, tmp, 1);
		}
		tmp++;
	}
}

/*
 * Function that attaches the command in the path
 */
int attach_path(char *cmd)
{
	char ret[100];
	int index;
	int fd;
	bzero(ret, 100);
	for(index=0;search_path[index]!=NULL;index++) {
		strcpy(ret, search_path[index]);
		strncat(ret, cmd, strlen(cmd));
		if((fd = open(ret, O_RDONLY)) > 0) {
			strncpy(cmd, ret, strlen(ret));
			close(fd);
			return 0;
		}
	}
	return 0;
}

/*
 * Function that copies the environment variables from the so
 */
void copy_envp(char **envp)
{
    int index = 0;
    for(;envp[index] != NULL; index++) {
        my_envp[index] = (char *)malloc(sizeof(char) * (strlen(envp[index]) + 1));
        memcpy(my_envp[index], envp[index], strlen(envp[index]));
    }
}

/*
 * Function that does the redirect operation (<, <<, >, >>, |)
 */
void redirect(void){

    int fd,child;
    char str[1024];
    FILE *fa;

    switch (op){

        case 1:
            if(child = fork())
                wait(NULL);
            else {
                if( (fd = open(my_argv[1],O_RDONLY, S_IWUSR | S_IRUSR)) < 0)
                    perror("Cannot create/open file\n");
                else {
                    close(STDIN_FILENO);
                    dup(fd);
                    close(fd);
                }
                execvp(my_argv[0], NULL);
            }
        
            break;
        case 2:
            if(child = fork())
                wait(NULL);
            else {
                fa = fopen(my_argv[1], "w");
                while(strcmp(str, my_argv[1]) != 0){
                    fgets(str, 1024, stdin);
                    fputs(str, fa);
                    str[strlen(str)-1] = '\0';                              
                }
                fclose(fa);
                if( (fd = open(my_argv[1],O_RDONLY, S_IWUSR | S_IRUSR)) < 0)
                    perror("Cannot create/open file\n");
                else {
                    close(STDIN_FILENO);
                    dup(fd);
                    close(fd);
                }
                remove(my_argv[1]);
                execvp(my_argv[0], NULL);
            }
            break;
        case 3:
            if(child = fork())
                wait(NULL);
            else {
                if( (fd = open(my_argv[1], O_CREAT | O_WRONLY, S_IWUSR | S_IRUSR)) < 0)
                    perror("Cannot create/open file\n");
                else {
                    close(STDOUT_FILENO);
                    dup(fd);
                    close(fd);
                }
                execvp(my_argv[0], NULL);
            }
        
            break;
        case 4:
            if(child = fork())
                wait(NULL);
            else {
                if( (fd = open(my_argv[1], O_CREAT | O_APPEND | O_WRONLY, S_IWUSR | S_IRUSR)) < 0)
                    perror("Cannot create/open file\n");
                else {
                    close(STDOUT_FILENO);
                    dup(fd);
                    close(fd);
                }
                execvp(my_argv[0], NULL);
            }
            break;
        case 5:

            break;
        default:
            break;
    }
        

}

/*
 * Function that does the parser in the command line
 */
void parser(char *tmp_argv)
{
	char *foo = tmp_argv;
    char *foo_op = tmp_argv;
	int index = 0;
	char ret[100];
    char ret_op[100];
        
	
    bzero(ret, 100);
    bzero(ret_op, 100);

	while ((*foo != '\0') && (*foo_op != '\0'))  {
		if(index == PARAM)
			break;
        
                
        if (*foo == ' '){
            if (my_argv[index] == NULL){  
			    my_argv[index] = (char *)malloc(sizeof(char) * strlen(ret) + 1);
			}else {
                bzero(my_argv[index], strlen(my_argv[index]));
            }
            strncpy(my_argv[index], ret, strlen(ret));
			strncat(my_argv[index], "\0", 1);
			bzero(ret, 100);
			index++;
		}else if (*(foo_op) == '<'){
            if (*(foo_op+1) == '<'){
                op = 1;
                foo_op++;
		
            }else{
                op = 2;
            }
            if (my_argv[index] == NULL){  
			    my_argv[index] = (char *)malloc(sizeof(char) * strlen(ret) + 1);
			}else {
                bzero(my_argv[index], strlen(my_argv[index]));
            }
            
			strncpy(my_argv[index], ret_op, strlen(ret));
			strncat(my_argv[index], "\0", 1);
			bzero(ret_op, 100);
			index++;
        }else if (*(foo_op+1) == '>'){
            if (*(foo_op+2) == '>'){
                op = 3;
                foo_op++;
            }else{
                op = 4;
            }
            if (my_argv[index] == NULL){  
			    my_argv[index] = (char *)malloc(sizeof(char) * strlen(ret) + 1);
			}else {
                bzero(my_argv[index], strlen(my_argv[index]));
            }
            strncpy(my_argv[index], ret_op, strlen(ret));
			strncat(my_argv[index], "\0", 1);
			bzero(ret_op, 100);
			index++;
        }else if (*(foo_op+1) == '|'){
            op = 5;
            if (my_argv[index] == NULL){  
			    my_argv[index] = (char *)malloc(sizeof(char) * strlen(ret) + 1);
			}else {
                bzero(my_argv[index], strlen(my_argv[index]));
            }
            strncpy(my_argv[index], ret_op, strlen(ret));
			strncat(my_argv[index], "\0", 1);
			bzero(ret_op, 100);
			index++;
        }else{
            strncat(ret, foo, 1);
            strncat(ret_op,foo_op,1);
		}
		foo++;
        foo_op++;
	}
	if ((ret[0] != '\0') || (ret_op[0] != '\0')){ 
		my_argv[index] = (char *)malloc(sizeof(char) * strlen(ret) + 1);
		strncpy(my_argv[index], ret, strlen(ret));
		strncat(my_argv[index], "\0", 1);
	}


}


/*
 * Main function
 */
int main(int argc, char **argv, char *envp[])
{
    int status;
    pid_t child;
    char tmp[MAXBUFFER],ret[100];
    char c;
    int i;
    char **tmp_argv;
    char *path_str = (char *)malloc(sizeof(char) * 256);
            	 
    
    signal(SIGINT, SIG_IGN);
    signal(SIGINT, handle_signal);
    

    bzero(tmp, sizeof(tmp));
    printf("gash> ");
            
    copy_envp(envp);
    get_path_string(my_envp, path_str);
    insert_path_str_to_search(path_str);
                      
    
    while(c != EOF) {
	
	    c = getchar();
	    switch(c) {
		    case '\n': 
                parser(tmp);
			    if( strncmp(tmp, "exit", 4) == 0) {
                    c = EOF;
                }else if (strncmp(tmp,"help",4) == 0){
                    

                }else if (strncmp(tmp,"cd",2) == 0){
                    if (chdir(my_argv[1]))
                        perror(my_argv[1]);
                              
                }else if (strncmp(tmp,"pwd",3) == 0){
                
                }else if (strncmp(tmp,"bg",2) == 0){

                }else if (strncmp(tmp,"fg",2) == 0){

                }

                else {
                    if(index(my_argv[0], '/') == NULL) {
                           if(attach_path(my_argv[0]) == 0) {
                                if( (child = fork()) ) {
                                    wait(NULL);
                                } else {
                                                
                                    execve(my_argv[0], my_argv, environ);
                                    printf("\nCannot execute: %s\n", tmp);
                            
                                }
                            }
                    }

                bzero(tmp, sizeof(tmp));
                bzero(my_argv, sizeof(my_argv));
                break;
            }			    
                
            default: strncat(tmp, &c, 1);
				    
		}
    }
    
    free(path_str);
    for(i=0;my_envp[i]!=NULL;i++)
        free(my_envp[i]);
    for(i=0;i<10;i++)
        free(search_path[i]);


    return(0);

}


